package gnssio

import (
	"dgo/goutils/dnet"
	"dgo/goutils/utils"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"time"
)

/*
 * 多个数据源通道, 优选选一个
 */
type CommMultiChannel struct {
	Caption     string
	listeners   *utils.SafeList
	cur_channel *CommMultiChannelSingle
	channel_map utils.GSyncMapGroup
}

var (
	sync_workers *utils.MultiGroupTask = nil
)

func checksyncWorkers() {
	if sync_workers == nil {
		sync_workers = utils.NewMultiGroupTask()
		sync_workers.ConfigMinWork(1)
		sync_workers.Start()
	}
}

func NewCommMultiChannel() *CommMultiChannel {
	rval := &CommMultiChannel{
		listeners: utils.NewSafeList(),
	}
	return rval
}

func CreateCommMultiChannelFromCmdLineFunc(args ...interface{}) (rval interface{}, err error) {
	if len(args) < 1 {
		return nil, errors.New("至少要传入一个参数")
	}
	cmdStr := args[0].(string)
	if len(cmdStr) == 0 {
		return nil, errors.New("命令参数非法")
	}
	return NewCommMultiChannelFromCmdLine(cmdStr)
}

/*
**

	multichannel://{"caption":"00", "list":[{"sn":1, "caption":"01", "cmdline":"xxxx", "cmdconf":"xxxx"}]}
*/
func NewCommMultiChannelFromCmdLine(cmdstr string) (*CommMultiChannel, error) {
	ocmdstr := cmdstr
	ok, cmdstr := utils.CheckTrimPrefix(cmdstr, "multichannel://")
	if !ok {
		return nil, errors.New(fmt.Sprintf("非法的[multichannel]配置:%s", ocmdstr))
	}

	if len(cmdstr) == 0 {
		return nil, errors.New(fmt.Sprintf("非法的[multichannel]配置:%s", ocmdstr))
	}
	conf, err := wrapper.NewValueFromJson([]byte(cmdstr), false, false)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("非法的[multichannel]配置:%s", ocmdstr))
	}
	cmc := NewCommMultiChannel()
	cmc.Caption = conf.AsString("caption", "")
	lst := conf.ValueByName("list")
	if lst == nil {
		return nil, errors.New(fmt.Sprintf("multichannel:配置非法, 缺少channel(list):%s", ocmdstr))
	}

	for i := 0; i < lst.Count(); i++ {
		itm1 := lst.ValueByIndex(i)
		comm, err := CreateCommFromCmdLineAndConf(itm1.AsString("cmdline", ""), itm1.AsString("cmdconf", ""))
		if err != nil {
			utils.Log.Warnf("channel配置[%s]非法:%s", itm1.String(), err.Error())
			continue
		} else if comm != nil {
			channel := cmc.AddChannel(itm1.AsInt("sn", i), itm1.AsString("caption", fmt.Sprintf("%.2d", i)), comm)
			channel.filterfirstrecv = itm1.AsInt("filterfirstrecv", 1)
			utils.Log.Infof("添加Channel[%d][%s]", channel.sn, channel.caption)
		}
	}

	return cmc, nil

}

func (this *CommMultiChannel) AddChannel(sn int, caption string, comm I_Comm) *CommMultiChannelSingle {
	channel := NewChannelSingle(comm)
	channel.owner = this
	channel.sn = sn
	channel.caption = caption
	this.channel_map.Set(channel, channel)
	return channel
}

func (this *CommMultiChannel) Remove(channel *CommMultiChannelSingle) {
	this.channel_map.Remove(channel)
	//channel.Close()
	channel.owner = nil
}

func (this *CommMultiChannel) rePick() {
	sync_workers.PostTaskFunc(this, func() {
		this.pickChannel()
	})
}

func (this *CommMultiChannel) OnChannelRecv(sender *CommMultiChannelSingle, buf []byte) {
	if this.cur_channel == nil {
		this.rePick()
		return
	}

	if !this.cur_channel.CanUse(time.Second * 5) { // 当前不能用了
		this.rePick()
		return
	}

	if this.cur_channel.sn > sender.sn {
		this.rePick()
	}

	if this.cur_channel != sender {
		return
	}

	this.listeners.ForEach(func(val interface{}) {
		val.(I_CommListener).OnReceive(this, buf, len(buf))
	})
}

func (this *CommMultiChannel) OnChannelConnect(sender *CommMultiChannelSingle) {
	this.rePick()
}

func (this *CommMultiChannel) OnChannelDisconnect(sender *CommMultiChannelSingle) {
	this.rePick()
}

func (this *CommMultiChannel) pickChannel() {
	val := this.channel_map.PickFirst(func(key, value interface{}) bool {
		itm := value.(*CommMultiChannelSingle)
		return itm.CanUse(time.Second * 5)
	}, func(iItm, jItm interface{}) bool {
		itm1 := iItm.(*CommMultiChannelSingle)
		itm2 := jItm.(*CommMultiChannelSingle)
		return itm1.sn < itm2.sn
	})
	if val == nil {
		this.cur_channel = nil
		utils.Log.Infof("[%s]没有任何通道连接", this.Caption)
	} else {
		exChannel := val.(*CommMultiChannelSingle)
		if exChannel != this.cur_channel {
			this.cur_channel = exChannel
			utils.Log.Infof("[%s]使用通道[%s]数据", this.Caption, exChannel.caption)
		}
	}
}

func (this *CommMultiChannel) SetOnRecv(event EventOnRecv) {

}

func (this *CommMultiChannel) SetOnDisEvent(event NotifyEvent) {

}

func (this *CommMultiChannel) SetOnConnectedEvent(event NotifyEvent) {

}

func (this *CommMultiChannel) QryStatus(action int) string {

	return ""
}

func (this *CommMultiChannel) onConnected(sender *dnet.ASyncTcpClient) {

}

func (this *CommMultiChannel) onDisconnected(sender *dnet.ASyncTcpClient) {

}

// =================================================================
func (this *CommMultiChannel) String() string {
	return ""

}

// =================================================================
func (this *CommMultiChannel) Start() {
	checksyncWorkers()
	this.channel_map.Range(func(key, value interface{}) bool {
		channel := value.(*CommMultiChannelSingle)
		channel.Start()
		return true
	})
}

func (this *CommMultiChannel) Stop() {
	this.channel_map.Range(func(key, value interface{}) bool {
		channel := value.(*CommMultiChannelSingle)
		utils.GoFunc2(channel.Stop)
		return true
	})
}

func (this *CommMultiChannel) Send(buf []byte, len int) int {
	utils.Log.Infof("[%s]不能进行数据发送", this.Caption)
	return 0
}

func (this *CommMultiChannel) AddListener(event I_CommListener) {
	if this.listeners.Exists(event) {
		utils.Log.Warn("I_CommListener已经存在请勿重复侦听")
		return
	}
	this.listeners.Add(event)
}

func (this *CommMultiChannel) RemoveListener(event I_CommListener) {
	this.listeners.Remove(event)
}
